package com.myway.service.impl;

import com.alibaba.fastjson.JSON;
import com.myway.core.execption.IBEException;
import com.myway.core.mapper.Mapper;
import com.myway.core.spring.SpringBeanUtil;
import com.myway.dao.*;
import com.myway.dto.common.JsonData;
import com.myway.dto.domain.IBEPassenger;
import com.myway.dto.domain.IBEPnr;
import com.myway.dto.domain.IBESegment;
import com.myway.dto.domain.PassengerType;
import com.myway.dto.ibe_param.Ticket;
import com.myway.dto.ibe_param.TicketSegment;
import com.myway.dto.order.domain.Inventory;
import com.myway.dto.order.domain.OrderStatus;
import com.myway.dto.order.domain.SegmentStatus;
import com.myway.dto.order.domain.TicketStatus;
import com.myway.dto.vo.*;
import com.myway.pojo.*;
import com.myway.service.IntegralService;
import com.myway.service.TicketService;
import com.myway.service.ibe.command.*;
import com.myway.service.ibe.config.IBEClientConfig;
import com.myway.service.ibe.param.RefundFormParam;
import com.myway.service.ibe.param.RefundParam;
import com.myway.utils.DateUtil;
import com.myway.utils.DateUtils;
import com.myway.utils.NumberGenerator;
import com.myway.utils.RandomUtil;
import com.myway.utils.eamil.EmailConfig;
import com.myway.utils.eamil.EmailUtils;
import com.myway.utils.htmltopdf.HtmlToPdfUtil;
import com.myway.utils.http.HttpsUtils_p12;
import com.travelsky.ibe.client.pnr.DETR;
import com.travelsky.ibe.client.pnr.DETRResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by wsq on 2018/8/14.
 */
@Service
@Slf4j
public class TicketServiceImpl implements TicketService {

    @Autowired
    private FlyOrderMapper flyOrderMapper;

    @Autowired
    private FlyTicketMapper flyTicketMapper;

    @Autowired
    private FlySegmentMapper flySegmentMapper;

    @Autowired
    private FlyPassengeMapper flyPassengeMapper;

    @Autowired
    private FlyPnrMapper flyPnrMapper;

    @Autowired
    private FlyRefundReversalMapper flyRefundReversalMapper;

    @Autowired
    private FlyPassengerSegmentMapper flyPassengerSegmentMapper;

    @Autowired
    private flyRebookruleMapper flyRebookruleMapper;

    @Autowired
    private IssueTicketCommand issueTicketCommand;//出票
    @Autowired
    private RefundTicketCommand refundTicketCommand;//退票
    @Autowired
    private PNRCommand pnrCommand;//pnr指令
    @Autowired
    private RetrievePNRCommand retrievePNRCommand;//提取pnr指令
    @Autowired
    private RetrieveTicketCommand retrieveTicketCommand;//pnr提取客票指令
    @Autowired
    private IntegralService integralService;
    @Autowired
    private DETRCommand detrCommand;


    public FlyOrder selectOrderDetailByOrderNo(String orderNo) {
        return flyOrderMapper.getFlyOrderById(orderNo);
    }

    @Override
    public JsonData handleTicket(String orderNo) {
        FlyOrder flyOrder = selectOrderDetailByOrderNo(orderNo);
        if (flyOrder.getOrderStatus().equalsIgnoreCase(OrderStatus.HP.getAlias()) || flyOrder.getOrderStatus().equalsIgnoreCase(OrderStatus.PI.getAlias())) {
            return ticketSuccess(orderNo);
        } else {
            //失败，将失败信息返回
            return ticketFailure(orderNo);
        }
    }

    public String getHtmlContent(Map<String, String> map) {
        String logoUrl = "<img src='http://47.75.92.162:48061/img/newlogo.png' width=\"150px\" height=\"100px;\"/>";
        if (!StringUtils.isEmpty(map.get("logoUrl"))) {
            logoUrl = "<img src='" + map.get("logoUrl") + "' width=\"150px\" height=\"100px;\"/>";
        }
        String orderId = map.get("orderId");
        String passenger = map.get("passenger");
        String issueDate = map.get("issueDate");
        String ticketNumber = map.get("ticketNumber");
        String PNR = map.get("PNR");
        String issuingAirline = map.get("issuingAirline");
        String issuedAgent = map.get("issuedAgent");
        System.out.println("—>>>>第一段数据封装完成");

        String flightDate = map.get("flightDate");
        String airlinePNR = map.get("airlinePNR");
        String flight = map.get("flight");
        String departureTime = map.get("departureTime");
        String arrivalTime = map.get("arrivalTime");
        String flightClass = map.get("flightClass");
        String meals = map.get("meals");
        String allow = map.get("allow");
        String flightStatus = "OK";

        String flightDate1 = map.get("flightDate1");
        String airlinePNR1 = map.get("airlinePNR1");
        String flight1 = map.get("flight1");
        String departureTime1 = map.get("departureTime1");
        String arrivalTime1 = map.get("arrivalTime1");
        String flightClass1 = map.get("flightClass1");
        String meals1 = map.get("meals1");
        String allow1 = map.get("allow1");
        String flightStatus1 = "OK";
        String flight2 = "";
        if (!StringUtils.isEmpty(flight1)) {
            flight2 = "<tr><td align=\"center\">" + flightDate1 + "</td><td align=\"center\">" + flight1 + "</td><td align=\"center\">" + departureTime1 + "</td>";
            flight2 += "<td align=\"center\">" + arrivalTime1 + "</td><td align=\"center\">" + flightClass1 + "</td><td align=\"center\">" + flightStatus1 + "</td><td align=\"center\">" + allow1 + "</td></tr>";
        }
        System.out.println("—>>>>第二段数据封装完成");

        String fare = map.get("fare");
        String tax = map.get("tax");
        String total = map.get("total");

        //退改签规则
        String rebookrule = map.get("rebookrule");

        StringBuffer stb = new StringBuffer();
        stb.append("<!DOCTYPE html>")
                .append("<html><body><meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\"><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"><title></title>")
                .append("<style type=\"text/css\">body {margin: 0;padding: 0;font-family: \"Hiragino Sans GB\", \"Microsoft YaHei\", \"WenQuanYi Micro Hei\", sans-serif;font-size: 14px;text-align: center;}</style>")
                .append("<div style=\"width:80%;text-align:left;margin: 0 auto;\">")
                .append("<p><table style=\"width:100%;\"><tr><td>" + logoUrl + "</td>")
                .append("<td style=\"width:50%;text-align:left;\"><h3>ITINERARY</h3></td></tr></table></p>")
                .append("<p><span style=\"background:#D3D3D3;\">&nbsp;&nbsp;Booking Details&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>")
                .append("----------------------------------------------------------------------------------------------------------------------------------------------------------<br/><br/>")
                .append("<table style=\"width:100%;\"><tr><th align=\"left\" style=\"padding-left:5px;padding-top:2px;width:130px;\">Order ID：</th><td align=\"left\" style=\"padding-left:5px;padding-top:2px;width:40%;\">")
                .append(orderId)
                .append("</td></tr><tr><th align=\"left\" style=\"padding-left:5px;padding-top:2px;width:130px;\">Passenger：</th><td align=\"left\" style=\"padding-left:5px;padding-top:2px;width:40%;\">")
                .append(passenger)
                .append("</td><th align=\"left\" style=\"padding-left:5px;padding-top:2px;width:130px;\">Issue Date：</th><td align=\"left\" style=\"padding-left:5px;padding-top:2px;\">")
                .append(issueDate)
                .append("</td></tr><tr><th align=\"left\" style=\"padding-left:5px;padding-top:2px;width:130px;\">Ticket Number：</th><td align=\"left\" style=\"padding-left:5px;padding-top:2px;width:40%;\">")
                .append(ticketNumber)
                .append("</td><th align=\"left\" style=\"padding-left:5px;padding-top:2px;width:130px;\">PNR:</th><td align=\"left\" style=\"padding-left:5px;padding-top:2px;\">")
                .append(PNR)
                .append("</td></tr><tr><th align=\"left\" style=\"padding-left:5px;padding-top:2px;width:130px;\">Issuing Airline:</th><td align=\"left\" style=\"padding-left:5px;padding-top:2px;width:40%;\">")
                .append(issuingAirline)
                .append("</td><th align=\"left\" style=\"padding-left:5px;padding-top:2px;width:130px;\">Issued Agent：</th><td align=\"left\" style=\"padding-left:5px;padding-top:2px;\">")
                .append(issuedAgent)
                .append("</td></tr></table><br/><br/></p>")

                .append("<p><span style=\"background:#D3D3D3;\">&nbsp;&nbsp;Flight Details&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>")
                .append("----------------------------------------------------------------------------------------------------------------------------------------------------------<br/><br/>")
                .append("<table border=\"1\" style=\"border-collapse:collapse;margin: 0 auto;padding: 0;font-family: 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif;font-size:14px;text-align: left;width:100%;\">")
                .append("<tr><th align=\"center\" style=\"padding:0px;margin:0px;\">Date</th>")
                .append("<th align=\"center\" style=\"padding:0px;margin:0px;\">Flight No</th><th align=\"center\" style=\"padding:0px;margin:0px;\">Departure Time<br/>Terminal</th>")
                .append("<th align=\"center\" style=\"padding:0px;margin:0px;\">Arrival Time<br/>Terminal</th><th align=\"center\" style=\"padding:0px;margin:0px;\">Class</th><th align=\"center\" style=\"padding:0px;margin:0px;\">Status</th><th align=\"center\" style=\"padding:0px;margin:0px;\">allow</th></tr>")
                .append("<tr><td align=\"center\">")
                .append(flightDate)
                /*.append("</td><td align=\"center\">")
                .append(airlinePNR)*/
                .append("</td><td align=\"center\">")
                .append(flight)
                .append("</td><td align=\"center\">")
                .append(departureTime)
                .append("</td><td align=\"center\">")
                .append(arrivalTime)
                .append("</td><td align=\"center\">")
                .append(flightClass)
                .append("</td><td align=\"center\">")
                .append(flightStatus)
                .append("</td><td align=\"center\">")
                .append(allow)
                .append("</td></tr>")
                .append(flight2)
                .append("</table><br/><br/></p>")

                .append("<p><span style=\"background:#D3D3D3;\">&nbsp;&nbsp;Payment Details&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>")
                .append("----------------------------------------------------------------------------------------------------------------------------------------------------------<br/><br/>")
                .append("<table><tr><th>Fare：</th><td>")
                .append(fare)
                .append("</td></tr><tr><th>Tax：</th><td>")
                .append(tax)
                .append("</td></tr><tr><th>Total：</th><td>")
                .append(total)
                .append("</td></tr></table><br/><br/></p>")


                .append("<p><span style=\"background:#D3D3D3;\">&nbsp;&nbsp;Fare Include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>")
                .append("----------------------------------------------------------------------------------------------------------------------------------------------------------<br/><br/>")
                .append("<table><tr><th>Flight departure meals：</th><td>")
                .append(meals);

                if (!StringUtils.isEmpty(meals1)) {
                    stb.append("</td></tr><tr><th>Return departure meals：</th><td>")
                            .append(meals1);
                }

           stb.append("</td></tr><tr><th>baggage：</th><td>")
                .append("10 KG HAND BAGGAGE ")
                .append("</td></tr></table><br/><br/></p>");


           stb.append("<p><span style=\"background:#D3D3D3;\">&nbsp;&nbsp;refund/change rules&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>")
                .append("----------------------------------------------------------------------------------------------------------------------------------------------------------<br/><br/><span>")
                .append(rebookrule)
                .append("</span></p>")


                .append("<p><span style=\"background:#D3D3D3;\">&nbsp;&nbsp;Notice&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>")
                .append("----------------------------------------------------------------------------------------------------------------------------------------------------------<br/><br/><span>")
                .append("• An electronic ticket has been issued for you. To receive a boarding pass please use check-in counters at the airport of departure. For identification please have your booking reference or the credit card which has been used at the time of booking ready.<br/>")
                .append("• We recommend to arrive at the airport 2 hours before departure for check-in.<br/>")
                .append("• Check-in is closed 45 minutes before departure.<br/>")
                .append("• Boarding is finalized 20 minutes before departure.<br/>")
                .append("• Please take note of the current free baggage allowance included in your ticket price and the applicable hand baggage regulations prior to your departure. If you are planning to take excess or special baggage with you, different conditions may apply.Please be advised that due to security reasons items which are classified as dangerous goods are prohibited on board.<br/>")
                .append("• Myway Airlines flight bookings do not require a reconfirmation after ticket purchase.<br/>")
                .append("• Please check the applicable visa and health entry requirements. Myway Airlines requires its passengers to have a valid passport and visa (if applicable) whilst traveling.<br/>")
                .append("• Passenger Notice - (link to website page)")
                .append("</span></p></div></body></html>");

        return stb.toString();
    }

    @Transactional
    public JsonData ticketSuccess(String orderNo) {

        System.out.println("客票信息处理...");
        try {
            //订单详情
            FlyOrder flyOrder = selectOrderDetailByOrderNo(orderNo);

            //根据订单获取到航段信息和旅客信息
            List<FlySegmentVo> segmentVos = flySegmentMapper.getFlySegmentByOrderId(flyOrder.getId() + "");
            List<FlyPassenge> passenges = flyPassengeMapper.getFlyPassengeByOrderId(String.valueOf(flyOrder.getId()));
            List<FlyPassengeVo> passengeVos = Mapper.getInstance(FlyPassengeVo.class, FlyPassenge.class).mapToValues(passenges);
            List<FlyPassengerSegmentVo> passengerSegmentVos = flyPassengerSegmentMapper.selectVoByOrderId(flyOrder.getId());
            List<FlyPnrVo> pnrlist = flyPnrMapper.findAllPnrByOrderID(flyOrder.getId());
            List<FlyPnrVo> adtPnrlist = flyPnrMapper.findPnrByOrderIDAndPassengerType(flyOrder.getId(), "1");//成人pnr
            List<FlyPnrVo> chdPnrList = flyPnrMapper.findPnrByOrderIDAndPassengerType(flyOrder.getId(), "2");//儿童pnr
            //获取最大的发票号
            String maxInvoiceNumber = flyOrderMapper.getMaxInvoiceNumber();

            //成人PNR数据封装
            inputPnrData(adtPnrlist,passengeVos,passengerSegmentVos,segmentVos);
            FlyOrderVo orderVo= new FlyOrderVo();
            orderVo=Mapper.getInstance(FlyOrderVo.class,FlyOrder.class).mapToValue(flyOrder);
            issueTicketForPnrList(adtPnrlist, "MJ", orderVo, false);//先出成人票
            if(CollectionUtils.isNotEmpty(chdPnrList)){
                //儿童PNR数据封装
                inputPnrData(chdPnrList,passengeVos,passengerSegmentVos,segmentVos);
                issueTicketForPnrList(chdPnrList, "MJ", orderVo, false);//后出儿童票、并添加成人票备注
            }
            //修改订单状态为已出票
            flyOrder.setOrderStatus(OrderStatus.PF.getAlias());

            String InvoicefligthNo = "MJ000";
            if (segmentVos != null && segmentVos.size() > 0 && !StringUtils.isEmpty(segmentVos.get(0).getFlightNo())) {
                InvoicefligthNo = segmentVos.get(0).getFlightNo();
            }
            String invoiceNumber = RandomUtil.getInvoiceNumber(InvoicefligthNo, maxInvoiceNumber);
            flyOrder.setInvoiceNumber(invoiceNumber);
            flyOrderMapper.updateByPrimaryKeySelective(flyOrder);
            JsonData jsonData = sendEmailInfo(maxInvoiceNumber, flyOrder, segmentVos, passenges, pnrlist, passengerSegmentVos);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return JsonData.fail(e.getMessage());
        }
        return JsonData.success("OK", "客票号返回成功");
    }

    public JsonData ticketFailure(String orderNo) {
        JsonData failMsg = JsonData.fail("IBE获取客票信息失败");
        return failMsg;
    }

    //PNR数据封装
    private void inputPnrData(List<FlyPnrVo> adtPnrlist, List<FlyPassengeVo> passengeVos, List<FlyPassengerSegmentVo> passengerSegmentVos, List<FlySegmentVo> segmentVos) {
        for (FlyPnrVo pnr : adtPnrlist) {
            for (FlyPassengeVo p : passengeVos) {
                if (pnr.getId().equals(p.getPnrId())) {
                    pnr.getPassengers().add(p);
                    for (FlyPassengerSegmentVo psvo : passengerSegmentVos) {
                        if (p.getId().equals(psvo.getPassengerId())) {
                            p.getPaxsegList().add(psvo);
                            for (FlySegmentVo segvo : segmentVos) {
                                if (psvo.getSegmentId().equals(segvo.getId())) {
                                    psvo.setSegment(segvo);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * @param pnrList
     * @param airline
     * @param o
     * @param isAuto
     * @名称：issueTicketForPnrList
     * @描述：对PNR集合进行出票
     */
    private void issueTicketForPnrList(List<FlyPnrVo> pnrList, String airline, FlyOrderVo o, boolean isAuto) {
        for (FlyPnrVo pnr : pnrList) {
            List<FlyPassengeVo> passengers = pnr.getPassengers();
            List<FlyPassengerSegmentVo> paxs = new ArrayList<FlyPassengerSegmentVo>();
            for (FlyPassengeVo passenger : passengers) {
                paxs.addAll(passenger.getPaxsegList());
                break;
            }
            List<FlySegmentVo> segments = new ArrayList<FlySegmentVo>();
            for (FlyPassengerSegmentVo pax : paxs) {
                segments.add(pax.getSegment());
            }
//			List<Segment> segments = segmentDao.findSegmentByPnrIdAndInventory(pnr.getId(), Inventory.IBE);
            Assert.notEmpty(segments, "No IBE segment can be found for PNR " + pnr.getPnrNo());

            if (!isAllSegmentCanceled(pnr, airline)) {
                // All segments in PNR is expected to be from IBE inventory
//                if (isAllSegmentFromIBE(segments)) {
                // Send command to IBE to issue ticket (asynchronously) if
                // all segments are from IBE inventory.
                List<FlyPassengeVo> paxList = new ArrayList<FlyPassengeVo>(passengers);
                issueTicket(pnr, segments, paxList, airline, o, isAuto);
                /*} else {
                    log.error("PNR "+ pnr.getPnrNo()+ " contains segment that does not belong to IBE inventory");
                    throw new HandlerException("PNR "+ pnr.getPnrNo()
                            + " contains segment that does not belong to IBE inventory");
                }*/
            } else if (isAllSegmentTicketed(pnr)) {
                //All segment ticketed but insurance fail,just issue insurance.
//                if(isAllSegmentFromIBE(segments)) {
                List<FlyPassengeVo> paxList = new ArrayList<FlyPassengeVo>(passengers);
                issueTicket(pnr, segments, paxList, airline, o, isAuto, true);
                /*} else {
                    log.error("PNR "+ pnr.getPnrNo()+ " contains segment that does not belong to IBE inventory");
                    throw new HandlerException("PNR "+ pnr.getPnrNo()
                            + " contains segment that does not belong to IBE inventory");
                }*/
            }
        }
    }

    private boolean isAllSegmentCanceled(FlyPnrVo pnr, String airline) {
        boolean result = true;

        for (FlyPassengeVo pax : pnr.getPassengers()) {
            for (FlyPassengerSegmentVo ps : pax.getPaxsegList()) {
                log.info(SegmentStatus.HK.toString());
                if (SegmentStatus.HK.toString().equals(ps.getStatus()) || ((SegmentStatus.HN.toString().equals(ps.getStatus())
                        || SegmentStatus.HL.toString().equals(ps.getStatus()) || SegmentStatus.SA.toString().equals(ps.getStatus())) && airline.equals("MJ"))) {
                    result = false;
                }
            }

        }

        return result;
    }

    private boolean isAllSegmentTicketed(FlyPnrVo pnr) {
        boolean result = false;
        for (FlyPassengeVo pax : pnr.getPassengers()) {
            for (FlyPassengerSegmentVo ps : pax.getPaxsegList()) {
                if (SegmentStatus.RR.toString() == ps.getStatus()) {
                    result = true;
                }
            }
        }
        return result;
    }

    private void issueTicket(FlyPnrVo pnr, List<FlySegmentVo> segments, List<FlyPassengeVo> passengers, String airline, FlyOrderVo order, boolean isAuto) {
        log.info("start to issueticket,orderId=" + order.getId() + ",orderNo=" + order.getOrderId() + ",PNR: " + pnr.getPnrNo() + " Segments count: " + segments.size() + " Passengers count: "
                + passengers.size());
        issueTicket(pnr, segments, passengers, airline, order, isAuto, false);
    }

    private void issueTicket(FlyPnrVo pnr, List<FlySegmentVo> segments, List<FlyPassengeVo> passengers, String airline, FlyOrderVo order, boolean isAuto, boolean forInsurance) {
        //异步MQ出票
        /*TicketIssuanceArtifact issuance = new TicketIssuanceArtifact(airline);
        issuance.setPnrNo(pnr.getPnrNo());
        issuance.setSegments(segments);
        issuance.setPassengers(passengers);
        issuance.setOrder(order);

        IBEProducer producer=this.ticketProducer;
        if(isAuto){
            producer=this.autoProducer;
            if(airline != null){
                if(airline.trim().toUpperCase().equals("EU")){
                    producer=this.euTicketProducer;
                }
            }
        }
        if(forInsurance) {
            issuance.setReconfirmed(true);
            issuance.setTicketIssued(true);
            issuance.setLocalTicketInfoUpdated(true);
            issuance = new TicketIssuanceArtifactForBookInsurance(issuance);
        }
        log.info("=TravelSkyIBEHandler issueTicket,开始发送出票消息到MQ,producer.getDestination= "+producer.getDestination()+",sending to activeMQ,pnrno="+issuance.getPnrNo()+",airlinecode="+issuance.getAirline()+" orderno="+(issuance.getOrder()!=null?issuance.getOrder().getOrderNo():" " ));
        producer.send(producer.getDestination(), issuance);
        log.info("=TravelSkyIBEHandler issueTicket,发送出票消息到MQ成功,producer.getDestination= "+producer.getDestination()+",sending to activeMQ,pnrno="+issuance.getPnrNo()+",airlinecode="+issuance.getAirline()+" orderno="+(issuance.getOrder()!=null?issuance.getOrder().getOrderNo():" " ));
    */

        try {
            //确认出票
            System.out.println("==========@@@@===>确认出票=======");
            pnrCommand.reconfirm(pnr.getPnrNo(), segments);
            //出票前检查信息是否一致
            boolean unmodified = pnrUnmodified(pnr.getPnrNo(), segments, passengers, airline, order);
            if (unmodified && !ticketIssued(pnr.getPnrNo(), airline)) {
                //出票
                Map<String, Object> params = new HashMap<String, Object>();
                params.put("PNRNo", pnr.getPnrNo());
                int international = Integer.valueOf(order.getInternational());
                params.put("international", international);
                issueTicketCommand.execute(params, airline);
            }
            //保存本地客票
            updateTicketInfo(pnr.getPnrNo(), airline);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void updateTicketInfo(String pnrNo, String airline) {
        try {
            Map<String, Object> params = new HashMap<String, Object>();
            params.put("PNRNo", pnrNo);
            retrieveTicketCommand.execute(params, airline);
            List<Ticket> ibeTickets = (List<Ticket>) params.get("Ticket");
            ibeTickets.size();
            log.debug("Retrieved " + ibeTickets.size() + " ticket(s) from IBE for PNR " + pnrNo);
            if (ibeTickets.size() > 0) {
                log.info("ibeTickets(" + pnrNo + "):" + JSON.toJSONString(ibeTickets));
            }
            for (Ticket ibeTicket : ibeTickets) {
                persistTicket(pnrNo, ibeTicket, airline);
            }
        } catch (Exception e) {
            throw new IBEException("Error during updating ticket information to local database for PNR " + pnrNo + ". " + e.getMessage(), e);
        }
    }

    /**
     * @param pnrNo
     * @param ibeTicket
     * @param airline
     * @名称：persistTicket
     * @描述：保存本地客票
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    private void persistTicket(String pnrNo, Ticket ibeTicket, String airline) {
        log.debug("Persist ticket " + ibeTicket.getTicketNo());
        FlyTicket t = new FlyTicket();
        Long segmentId = null;
        String[] nos = ibeTicket.getTicketNo().split("-");
        Assert.isTrue(nos.length == 2, "Failed to parse IBE ticket number " + ibeTicket.getTicketNo());
        t.setIssCode(nos[0]);
        t.setTicketNo(nos[1]);
        t.setBookTime(new Date());
        t.setCk(NumberGenerator.generateRandomNumber(1));
        t.setConjunctionTkt(ibeTicket.getConjunctionTkt());
        t.setEndorsement("");
        t.setBspType("1");
        t.setPrintStatus("0");
        // Add ticket
        Long ticketId = this.addTicket(t, airline);
        // Find all passenger segments from local database based on PNR no and the name, certificate no specified in the
        // IBE ticket.
        log.debug("Retrieving passenger segment for " + ibeTicket.getPassengerName() + " (" + ibeTicket.getCertificateNo() + ") in PNR " + pnrNo);
        log.debug("tiketId:" + ticketId);
        String passgName = ibeTicket.getPassengerName();
        if (passgName != null) {
            passgName = passgName.toUpperCase();
            if (passgName.indexOf("INF(") > 0) {
                passgName = passgName.substring(0, passgName.indexOf("INF("));
                passgName = passgName.trim();//去婴儿姓名后的空格
            }
        }
        List<FlyPassengerSegmentVo> ibePsList = flyPassengerSegmentMapper.findPassengerSegmentByNameAndPnrAndInventory(passgName, pnrNo, Inventory.IBE);
        for (FlyPassengerSegmentVo ibeSeg : ibePsList) {
            FlySegmentVo segvo = flySegmentMapper.selectVoByPrimaryKey(ibeSeg.getSegmentId());
            ibeSeg.setSegment(segvo);
        }
        log.debug(ibePsList.size() + " passenger segment(s) for passenger " + ibeTicket.getPassengerName());
        // Update segment status, ticket status and ticket for each passenger segment
        List<Long> psIdList = new ArrayList<Long>();
        for (FlyPassengerSegmentVo ps : ibePsList) {
            if (!ps.getStatus().equals(SegmentStatus.XX)) {
                if (segmentInIBETicket(ps, ibeTicket)) {
                    psIdList.add(ps.getId());
                }
                if (segmentId == null) {
                    segmentId = ps.getSegmentId();
                }
            }
        }
        //默认本票号段出票
        if (!psIdList.isEmpty()) {
            log.debug("Update status and ticket for " + psIdList.size() + " passenger segment(s)");
            Long[] psIds = psIdList.toArray(new Long[psIdList.size()]);
            //把电子客票和PassengerSegment绑定
            this.updatePassengerSegment(ticketId, SegmentStatus.RR, TicketStatus.OPEN_FOR_USE, psIds);
        }
    }

    private boolean segmentInIBETicket(FlyPassengerSegmentVo paxSeg, Ticket ibeTicket) {
        List<TicketSegment> tsList = ibeTicket.getSegments();
        for (TicketSegment ts : tsList) {
            if ((ts.getFlightNo() == null ||
                    paxSeg.getSegment().getFlightNo().equals(ts.getFlightNo()))
                    && paxSeg.getSegment().getDepCode().equals(ts.getDepAirportCode())
                    && paxSeg.getSegment().getArrCode().equals(ts.getArrAirportCode())
                    && (null == ts.getDepTime()
                    || DateUtils.dateToString(paxSeg.getSegment().getDepTime(), "yyyy-MM-dd")
                    .equals(DateUtils.dateToString(ts.getDepTime(), "yyyy-MM-dd")))
                    && (!(paxSeg.getTicketStatus() != null && paxSeg.getTicketStatus().equals(TicketStatus.SUSPENDED))
                    && !(ts.getTicketStatus().equals("VOID") || ts.getTicketStatus().equals("REFUNDED")
                    || ts.getTicketStatus().equals("EXCHANGED") || ts.getTicketStatus().equals("SUSPENDED")))) {
                //注意修改！！！
                //&& paxSeg.getSegment().getCabinClass().substring(0, 1).equals( String.valueOf( ts.getCabin() ).substring(0, 1) )
                return true;
            }
        }
        return false;
    }

    /**
     * {@inheritDoc}
     */
    public Long addTicket(FlyTicket ticket, String airline) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("issCode", ticket.getIssCode());
        map.put("ticketNo", ticket.getTicketNo());
        DETRResult result = null;
        DETR detr = new DETR();
        String date = null;
        Date issueDate = null;
        try {
            pnrCommand.configIBEClient(detr, airline);
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            date = format.format(new Date());
            //FIXME [IBE] 根据票号提取电子客票行程单 生产环境
            result = detr.getScheduleByTktNo(ticket.getIssCode() + ticket.getTicketNo());
            date = format.format(result.getIssueDate());
            ticket.setAgentCode(result.getOfficeCode());
            ticket.setIssuedBy(result.getIssueAirline());
            if (date == null) {
                return null;
            }
            issueDate = format.parse(date);
            //避免oracle日期出错
            issueDate = DateUtils.convertOracleDate(issueDate);
            map.put("issuedDate", date);
            ticket.setIssuedDate(issueDate);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        List<FlyTicket> ts = flyTicketMapper.findTicketByTicketNo(map);
        if (ts == null || ts.isEmpty()) {
            if (ticket.getBookTime() == null || DateUtils.dateToString(ticket.getBookTime()).equals("")) {
                log.info("Ticket:" + ticket.getIssCode() + "-" + ticket.getTicketNo() + " BOOKTIME is null");
                ticket.setBookTime(DateUtils.convertOracleDate(new Date()));
            }
            if (ticket.getIssuedDate() == null || DateUtils.dateToString(ticket.getBookTime()).equals("")) {

                String dateNow = "";
                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
                dateNow = format.format(new Date());
                try {
                    log.info("Ticket:" + ticket.getIssCode() + "-" + ticket.getTicketNo() + " IssuedDate is null");
                    ticket.setIssuedDate(DateUtils.convertOracleDate(format.parse(dateNow)));
                } catch (ParseException e) {
                    e.printStackTrace();
                    log.info("ticket:" + ticket.getIssCode() + ticket.getTicketNo() + "generate issued date error");
                }
            }
            flyTicketMapper.insertSelective(ticket);
        } else {
            FlyTicket t1 = ts.get(0);
            ticket.setId(t1.getId());
        }
        return ticket.getId();
    }

    public void updatePassengerSegment(Long ticketId, SegmentStatus segmentStatus, TicketStatus ticketStatus, Long... paxSegIds) {
        FlyTicket t = flyTicketMapper.selectByPrimaryKey(ticketId);
        for (Long paxSegId : paxSegIds) {
            FlyPassengerSegment ps = flyPassengerSegmentMapper.selectByPrimaryKey(paxSegId);
            ps.setTicketId(t.getId());
            //SA航段，不需要更新成RR
            if (ps.getStatus() == SegmentStatus.SA.toString()) {
                segmentStatus = SegmentStatus.SA;
            }
            ps.setStatus(segmentStatus.toString());
            ps.setTicketStatus(ticketStatus.toString());
            flyPassengerSegmentMapper.updateByPrimaryKeySelective(ps);
        }
    }

    /**
     * <pre>出票前检查PNR：航段、舱位、承运人及旅客姓名是否与本地信息一致</pre>
     *
     * @param
     * @return
     * @Auther 郑兴(zhengxing)
     */
    private boolean pnrUnmodified(String pnrNo, List<FlySegmentVo> segments, List<FlyPassengeVo> passengers, String airline, FlyOrderVo order) {
        boolean unmodified = true;
        IBEPnr pnrtemp = new IBEPnr();
        int index = 0;
        IBEPnr pnr = new IBEPnr();
//        if(ContextConfig.isOnline){//FIXME [IBE] 出票前检查PNR
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("PNR", pnrNo);
        retrievePNRCommand.execute(params);
        pnr = (IBEPnr) params.get("IBEPnr");
//        }
        for (IBESegment tempSegment : pnr.getSegments()) {
            if (!"ARNK".equals(tempSegment.getFlightNo())) {
                pnrtemp.getSegments().add(index, tempSegment);
                index++;
            }
        }
        //航段数量,旅客数量(不含婴儿)必须一致
        if (null != pnr && pnrtemp.getSegments().size() <= segments.size() /*&&
                pnr.getPassengers().size() == artifact.getPassengers().size()*/) {
            boolean isChild = false;
            pnrtemp.setPassengers(pnr.getPassengers());
            //检查旅客
            for (IBEPassenger ip : pnrtemp.getPassengers()) {
                boolean paxMatched = false;
                for (FlyPassengeVo p : passengers) {
                    String userName = ip.getName();
                    if (userName.toUpperCase().endsWith("CHD")) {
//						userName = userName.substring(0, userName.length() - 3);
                    }
                    String pName = formatName(p.getXingE(), p.getMingE()).toUpperCase();
                  /*  String pName = (p.getXingE() + "/" + p.getMingE()).toUpperCase();*/
                    //PGSGS-1375  当姓名后有JC和GM时取匹配时少取后两个字符
                    if ((pName.endsWith("JC") || pName.endsWith("GM")) && order.getAirlineCode().equals("MJ")) {
                        pName = pName.substring(0, pName.length() - 2);
                    }

                    //旅客姓名必须一致
                    if (userName.equals(pName)) {
                        paxMatched = true;
                        if (p.getPassageType() == PassengerType.CHILD) {
                            isChild = true;
                        }
                        break;
                    }
                }
                //未匹配到对应旅客，表示PNR已被修改
                if (!paxMatched) {
                    log.warn("pnrUnmodified(false):未匹配到对应旅客，不能进行出票!");
                    return false;
                }
            }
            //检查航段
            for (IBESegment is : pnrtemp.getSegments()) {
                boolean segMatched = false;
                for (FlySegmentVo s : segments) {
                    log.info(String.valueOf(is.getFltClass() == s.getCabinClass().charAt(0)));
                    //承运人、航段、舱位必须一致
                    if (is.getFlightNo().substring(0, 2).equals(s.getFlightNo().substring(0, 2)) &&
                            is.getOrgCity().equals(s.getDepCode()) &&
                            is.getDesCity().equals(s.getArrCode()) &&
                            (is.getFltClass() == s.getCabinClass().charAt(0) || (isChild && is.getFltClass() == 'Y'))) {
                        segMatched = true;
                        break;
                    }
                }
                //未匹配到对应航段，表示PNR已被修改
                if (!segMatched) {
                    log.warn("pnrUnmodified(false):未匹配到对应航段，不能进行出票!");
                    return false;
                }
            }
        } else {
            unmodified = false;
        }
        log.info("出票前检查PNR pnrUnmodified:" + unmodified);
        return unmodified;
    }

    /**
     * @param
     * @return
     * @名称：ticketIssued
     * @描述：PNR是否已出票
     */
    private boolean ticketIssued(String pnrNo, String airline) {
        boolean issued = false;
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("PNRNo", pnrNo);
        retrieveTicketCommand.execute(params, airline);
        List<Ticket> tickets = (List<Ticket>) params.get("Ticket");
        if (CollectionUtils.isNotEmpty(tickets)) {
            log.debug(tickets.size() + " ticket(s) have been issued for PNR " + pnrNo);
            issued = true;
        }
        log.info("PNR是否已出票(ticketIssued):" + issued);
        return issued;
    }

    @Override
    public JsonData selectVoByPrimaryKey(Long orderId) {
        return JsonData.success(flyTicketMapper.selectVoByPrimaryKey(orderId));
    }


    public JsonData sendEmailInfo(String invoiceNumber, FlyOrder flyOrder, List<FlySegmentVo> segmentVos, List<FlyPassenge> passenges, List<FlyPnrVo> pnrlist, List<FlyPassengerSegmentVo> passengerSegmentVos) throws Exception {
        Map<String, String> map = new HashMap<String, String>();
        Map<String, String> attachMap = new HashMap<String, String>();

        try {
            String passengerStr = "";
            BigDecimal fares = new BigDecimal(0.00);
            BigDecimal taxs = new BigDecimal(0.00);
            List<String> ticketNoList = new ArrayList<String>();
            if (passenges != null && passenges.size() > 0) {
                for (FlyPassenge flyPassengeObj : passenges) {
                    String id = String.valueOf(flyPassengeObj.getId());
                    String xingE = StringUtils.isEmpty(flyPassengeObj.getXingE()) ? "" : flyPassengeObj.getXingE();
                    String mingE = StringUtils.isEmpty(flyPassengeObj.getMingE()) ? "" : flyPassengeObj.getMingE();
                    passengerStr += xingE + "/" + mingE;
                    List<String> ticketNoArr = flyPassengerSegmentMapper.getTicketNoByPassengerId(flyPassengeObj.getId() + "", flyOrder.getId() + "");
                    for (String str : ticketNoArr) {
                        ticketNoList.add(str);
                    }
                    if (passengerSegmentVos != null && passengerSegmentVos.size() > 0) {
                        for (FlyPassengerSegmentVo flyPassengerSegmentVo : passengerSegmentVos) {
                            String passengerId = String.valueOf(flyPassengerSegmentVo.getPassengerId());
                            if (!StringUtils.isEmpty(id) && id.equals(passengerId)) {
                                fares = fares.add(flyPassengerSegmentVo.getMarketFare());//基本票价
                                taxs = taxs.add(flyPassengerSegmentVo.getOtherTaxes());//税费
                                break;
                            }
                        }
                    }
                }
            }

            String ticketNumberStr = "";
            String allow="";
            String allow1="";
            if (ticketNoList != null && ticketNoList.size() > 0) {
                HashSet h = new HashSet(ticketNoList);
                ticketNoList.clear();
                ticketNoList.addAll(h);
                for (String str : ticketNoList) {
                    ticketNumberStr += str + ",";
                }
                String ticketNoOne = ticketNoList.get(0);
                allow=detrCommand.getBaggage(ticketNoOne, 0);
                if(segmentVos.size()==2){
                    if(ticketNoList.size()>1){
                        allow1=detrCommand.getBaggage(ticketNoList.get(1), 1);
                    }else{
                        allow1=detrCommand.getBaggage(ticketNoOne, 1);
                    }
                }
                ticketNumberStr = ticketNumberStr.substring(0, ticketNumberStr.length() - 1);
            }

            map.put("ticketNumber", ticketNumberStr); //票号
            map.put("passenger", StringUtils.isEmpty(passengerStr) ? "" : passengerStr);
            SimpleDateFormat sdf = new SimpleDateFormat("d-MMM-yy", Locale.ENGLISH);
            SimpleDateFormat sdfTime = new SimpleDateFormat("HH:mm");
            map.put("issueDate", StringUtils.isEmpty(flyOrder.getSetDate()) ? "" : sdf.format(flyOrder.getSetDate()));
            map.put("orderId", StringUtils.isEmpty(flyOrder.getOrderId()) ? "" : flyOrder.getOrderId());

            String pnrStr = "";
            if (pnrlist != null && pnrlist.size() > 0) {
                for (FlyPnrVo flyPnrVoObj : pnrlist) {
                    pnrStr += flyPnrVoObj.getPnrNo() + ",";
                }
            }
            map.put("PNR", StringUtils.isEmpty(pnrStr) ? "" : pnrStr.substring(0, pnrStr.length() - 1));
            map.put("issuingAirline", "Myway Airlines");
            map.put("issuedAgent", "TBS319"); //发行代理人

            String enRules = "";
            if (segmentVos != null && segmentVos.size() > 0) {
                map.put("flightDate", StringUtils.isEmpty(segmentVos.get(0).getDepTime()) ? "" : sdf.format(segmentVos.get(0).getDepTime()));
                map.put("airlinePNR", StringUtils.isEmpty(pnrStr) ? "" : pnrStr.substring(0, pnrStr.length() - 1));
                map.put("flight", StringUtils.isEmpty(segmentVos.get(0).getFlightNo()) ? "" : segmentVos.get(0).getFlightNo());
                map.put("departureTime", segmentVos.get(0).getDepCode() + "-" + segmentVos.get(0).getDepCodeName() + "<br/>" + sdfTime.format(segmentVos.get(0).getDepTime()));
                map.put("arrivalTime", segmentVos.get(0).getArrCode() + "-" + segmentVos.get(0).getArrCodeName() + "<br/>" + sdfTime.format(segmentVos.get(0).getArrTime()));
                map.put("flightClass", segmentVos.get(0).getCabinClass());
                map.put("allow", allow);
                if ("true".equals(segmentVos.get(0).getMeals())) {
                    map.put("meals", "Support for meals");
                } else {
                    map.put("meals", "Meals are not supported");
                }
                if (segmentVos.size() == 2) {
                    map.put("flightDate1", StringUtils.isEmpty(segmentVos.get(1).getDepTime()) ? "" : sdf.format(segmentVos.get(1).getDepTime()));
                    map.put("airlinePNR1", StringUtils.isEmpty(pnrStr) ? "" : pnrStr.substring(0, pnrStr.length() - 1));
                    map.put("flight1", StringUtils.isEmpty(segmentVos.get(1).getFlightNo()) ? "" : segmentVos.get(1).getFlightNo());
                    map.put("departureTime1", segmentVos.get(1).getDepCode() + "-" + segmentVos.get(1).getDepCodeName() + "<br/>" + sdfTime.format(segmentVos.get(1).getDepTime()));
                    map.put("arrivalTime1", segmentVos.get(1).getArrCode() + "-" + segmentVos.get(1).getArrCodeName() + "<br/>" + sdfTime.format(segmentVos.get(1).getArrTime()));
                    map.put("flightClass1", segmentVos.get(1).getCabinClass());
                    map.put("allow1", allow1);
                    if ("true".equals(segmentVos.get(1).getMeals())) {
                        map.put("meals1", "Support for meals");
                    } else {
                        map.put("meals1", "Meals are not supported");
                    }
                }
                flyRebookrule flyRebookrule = new flyRebookrule();
                flyRebookrule.setCabin(segmentVos.get(0).getCabinClass());
                flyRebookrule.setFlyNumber(segmentVos.get(0).getFlightNo());
                flyRebookrule.setOneway("1");
                flyRebookrule rebookrule1 = flyRebookruleMapper.selectRules(flyRebookrule);
                if (rebookrule1 != null && !StringUtils.isEmpty(rebookrule1.getEnRules())) {
                    String enRules1 = rebookrule1.getEnRules();
                    enRules = enRules1.replaceAll(";", "<br/>");
                }
            } else {
                map.put("flightDate", "");
                map.put("airlinePnr", "");
                map.put("flightNo", "");
                map.put("departureTime", "");
                map.put("arrivalTime", "");
                map.put("flightClass", "");
            }

            map.put("total", String.valueOf(flyOrder.getTotalPrice()));
            map.put("fare", String.valueOf(fares));
            map.put("tax", String.valueOf(taxs));
            map.put("rebookrule", enRules);

            String htmlContext = getHtmlContent(map);
            System.out.println("email context - " + new Date() + ">" + htmlContext);
            String toEmail = flyOrder.getContactEmail();
            String subjectStr = "Myway ticket information";

            //附件map
            attachMap.put("company", "Myway Airlines Co., Ltd");
            String invoiceNumberreplace = invoiceNumber.replaceAll("_", "");
            attachMap.put("invoiceNumber", invoiceNumberreplace);
            attachMap.put("address", "Georgia, Tbilisi, Isani-Samgori district, Varketili 3, Near IV m/d, Plot 14/428, 14/429, Vazisubani sett., III M/D, II block, Near building N11");
            attachMap.put("pnr", StringUtils.isEmpty(pnrStr) ? "" : pnrStr.substring(0, pnrStr.length() - 1));
            attachMap.put("vat", "406178835");
            attachMap.put("rebookrule", enRules);

            SimpleDateFormat bookingDateSdfTime = new SimpleDateFormat("dd.MM.yyyy");
            attachMap.put("bookingDate", StringUtils.isEmpty(flyOrder.getSetDate()) ? "" : bookingDateSdfTime.format(flyOrder.getSetDate()));
            StringBuffer passengerAndTicketNoSb = new StringBuffer();
            if (passenges != null && passenges.size() > 0) {
                for (FlyPassenge flyPassengeObj : passenges) {
                    String xingE = StringUtils.isEmpty(flyPassengeObj.getXingE()) ? "" : flyPassengeObj.getXingE();
                    String mingE = StringUtils.isEmpty(flyPassengeObj.getMingE()) ? "" : flyPassengeObj.getMingE();
                    passengerAndTicketNoSb.append("<tr><td>");
                    passengerAndTicketNoSb.append(xingE + "/" + mingE + "</td><td>");
                    List<String> ticketNoArr = flyPassengerSegmentMapper.getTicketNoByPassengerId(flyPassengeObj.getId() + "", flyOrder.getId() + "");
                    passengerAndTicketNoSb.append(ticketNoArr.size() > 0 ? ticketNoArr.get(0) : "");
                    passengerAndTicketNoSb.append("</td></tr>");
                }
            }
            attachMap.put("name", passengerAndTicketNoSb.toString());

            StringBuffer segmentSb = new StringBuffer();
            SimpleDateFormat friSdfTime = new SimpleDateFormat("dd.MM");
            SimpleDateFormat HHmmSdfTime = new SimpleDateFormat("HH:mm");
            SimpleDateFormat weekSdfTime = new SimpleDateFormat();
            if (segmentVos != null && segmentVos.size() > 0) {
                for (FlySegmentVo flySegmentVo : segmentVos) {
                    segmentSb.append("<tr><th style=\"text-align: left;padding:5px 10px;\">")
                            .append(DateUtil.dateToWeek(weekSdfTime.format(flySegmentVo.getDepTime())) + " " + friSdfTime.format(flySegmentVo.getDepTime()))
                            .append("</th><th>")
                            .append(flySegmentVo.getFlightNo())
                            .append("</th><th>")
                            .append(HHmmSdfTime.format(flySegmentVo.getDepTime()) + " " + flySegmentVo.getDepCodeName())
                            .append("</th><th>")
                            .append(HHmmSdfTime.format(flySegmentVo.getArrTime()) + " " + flySegmentVo.getArrCodeName())
                            .append("</th><th style=\"text-align: right;padding:5px 10px;\">")
                            .append("Cabin Class: " + flySegmentVo.getCabinClass())
                            .append("</th></tr>");
                }
            }
            attachMap.put("param1", segmentSb.toString());
            attachMap.put("total", String.valueOf(flyOrder.getTotalPrice()));
         /*   String ticketNumber = map.get("ticketNumber");*/
            attachMap.put("fare", String.valueOf(fares));
            attachMap.put("taxes", String.valueOf(taxs));
            SimpleDateFormat invoiceSdfTime = new SimpleDateFormat("dd.MM.yy HH:mm");
            attachMap.put("invoiceDateUtc", invoiceSdfTime.format(new Date()));
            String attachmentHtml = HtmlToPdfUtil.returnHtmlContent(attachMap);

            String fileOutPath = ContextLoader.getCurrentWebApplicationContext().getServletContext().getRealPath("/files");
            String pdfName = flyOrder.getOrderId() + ".pdf";
            fileOutPath += "/" + pdfName;
            boolean attachmentResult = HtmlToPdfUtil.htmlToPdf(attachmentHtml, fileOutPath);
            System.out.println("get file - " + new Date() + ">" + fileOutPath);
            Properties fileprops = PropertiesLoaderUtils.loadProperties(new ClassPathResource("emailconfig.properties"));
            EmailUtils.sendHtmlEmail(toEmail, subjectStr, htmlContext, fileOutPath);
            return JsonData.success();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return JsonData.fail(e.getMessage());
        }

    }

    private String formatName(String xing, String ming) {
        String name = "";
        if (xing.length() > 26 && ming.length() > 26) {
            name = xing.substring(0, 20) + "/" + ming.substring(0, 7);
        } else if (xing.length() > 26) {
            name = xing.substring(0, (27 - ming.length())) + "/" + ming;
        } else if (ming.length() > 26) {
            name = xing + "/" + ming.substring(0, (27 - xing.length()));
        } else {
            name = xing + "/" + ming;
        }
        return name;
    }

    //废票&&退款
    public JsonData ticketRefund(String orderNo) {
        FlyOrder order = flyOrderMapper.selectByPrimaryKey(Long.valueOf(orderNo));
        if (order != null && order.getOrderStatus().equalsIgnoreCase(OrderStatus.RD.toString())) {
            List<FlyPassenge> passenges = flyPassengeMapper.getFlyPassengeByOrderId(orderNo);
            List<FlyPassengeVo> passengeVos = Mapper.getInstance(FlyPassengeVo.class, FlyPassenge.class).mapToValues(passenges);
            for (FlyPassengeVo passenge : passengeVos) {
                List<FlyPassengerSegment> flyPassengerSegments = flyPassengerSegmentMapper.selectByOrderIdAndPassengerId(order.getId(), passenge.getId());
                for (int i = 1; i <= flyPassengerSegments.size(); i++) {
                    FlyPassengerSegment flyPassengerSegment = flyPassengerSegments.get(i - 1);
                    if (flyPassengerSegment.getStatus().equals(SegmentStatus.RR.toString()) && flyPassengerSegment.getTicketStatus().equals(TicketStatus.OPEN_FOR_USE.toString())) {
                        FlyTicket flyTicket = flyTicketMapper.selectByPrimaryKey(flyPassengerSegment.getTicketId());
                        FlyPnr flyPnr = flyPnrMapper.selectByPrimaryKey(passenge.getPnrId());
                        try {
                            if (flyTicket == null)
                                throw new Exception("flyTicket null");
                            if (flyPnr == null)
                                throw new Exception("flyPnr null");
                            String result = "";
                            if (refundTicketCommand.ticketIsUse(flyTicket.getIssCode() + "-" + flyTicket.getTicketNo())) {
                                result = refundTicketCommand.vt(flyTicket.getIssCode() + "-" + flyTicket.getTicketNo(), flyPnr.getPnrNo());
                                if (!result.equals("OK"))
                                    throw new Exception("Ticket Refund no OK");
                            }
                            flyPassengerSegment.setTicketStatus(TicketStatus.REFUNDED.toString());
                            flyPassengerSegment.setStatus(SegmentStatus.XX.toString());
                            flyPassengerSegmentMapper.updateByPrimaryKeySelective(flyPassengerSegment);
                            if (pnrCommand.pnrExist(flyPnr.getPnrNo()))
                                pnrCommand.cancelPnr(flyPnr.getPnrNo());
                        } catch (Exception e) {
                            System.out.println("退票异常 orderId:" + order.getOrderId());
                            log.error(e.getMessage(), e);
                            return JsonData.fail("Ticket Refund Failed orderId:" + order.getOrderId());
                        }
                    } else {
                        return JsonData.fail("Order not Issued orderId:" + order.getOrderId());
                    }
                }
            }
            FlyRefundReversal flyRefundReversal = flyRefundReversalMapper.getByOrderId(Long.valueOf(orderNo));
            String callBackResultStr = "";
            double amountDou = flyRefundReversal.getAmount() * 100;
            int amountInt = (new Double(amountDou)).intValue();
            String amount = String.valueOf(amountInt);
            try {
                callBackResultStr = HttpsUtils_p12.reversal(order.getFirstTransId(), amount);
            } catch (Exception e) {
                return JsonData.fail("Order Refund Failed orderId:" + order.getOrderId());
            }
            callBackResultStr = callBackResultStr.replaceAll("(\r\n|\r|\n|\n\r)", "<br>");
            if (callBackResultStr == null || callBackResultStr == "")
                return JsonData.fail("Order Refund Failed orderId:" + order.getOrderId());
            Map<String, String> callBackMap = new HashMap<String, String>();
            String[] data1 = callBackResultStr.split("<br>");
            if (data1 != null && data1.length > 0) {
                for (String s : data1) {
                    String[] data2 = s.split(":");
                    if (data2 != null && data2.length > 0)
                        callBackMap.put(data2[0].trim(), data2[1].trim());
                }
            }
            String result = callBackMap.get("RESULT"), result_code = callBackMap.get("RESULT_CODE"), refund_trans_id = callBackMap.get("REFUND_TRANS_ID");
            flyRefundReversal.setRefundStatus(result);
            flyRefundReversal.setRefundTransId(refund_trans_id);
            flyRefundReversal.setResult(callBackResultStr);
            flyRefundReversal.setRefoundTime(new Date());
            flyRefundReversalMapper.updateByPrimaryKeySelective(flyRefundReversal);
            if (callBackResultStr.toUpperCase().indexOf("ERROR") > -1 || org.apache.commons.lang3.StringUtils.isBlank(result) || !result.equals("OK"))
                return JsonData.fail("Order Refund Failed orderId:" + order.getOrderId());
            refundMail(orderNo, order.getContactEmail());
            order.setOrderStatus(OrderStatus.RF.toString());
            flyOrderMapper.updateByPrimaryKeySelective(order);
            integralService.refundIntegral(String.valueOf(order.getId()));
            return JsonData.success(null, "Order Refund Success!");
        } else {
            return JsonData.fail("Order Status Failed orderId:" + order.getOrderId());
        }
    }

    //退票&&退款
    public JsonData refundTicket(String orderNo) {
        FlyOrder order = flyOrderMapper.selectByPrimaryKey(Long.valueOf(orderNo));
        if (order != null && order.getOrderStatus().equalsIgnoreCase(OrderStatus.RD.toString())) {
            FlyRefundReversal flyRefundReversal = flyRefundReversalMapper.getByOrderId(Long.valueOf(orderNo));
            double orderPrice = order.getTotalPrice(), refundPrice = flyRefundReversal.getAmount(), rest = flyRefundReversal.getAmount();
            List<FlyPassenge> passenges = flyPassengeMapper.getFlyPassengeByOrderId(orderNo);
            List<FlyPassengeVo> passengeVos = Mapper.getInstance(FlyPassengeVo.class, FlyPassenge.class).mapToValues(passenges);
            int j = 0;
            for (FlyPassengeVo passenge : passengeVos) {
                j++;
                List<FlyPassengerSegment> flyPassengerSegments = flyPassengerSegmentMapper.selectByOrderIdAndPassengerId(order.getId(), passenge.getId());
                for (int i = 1; i <= flyPassengerSegments.size(); i++) {
                    FlyPassengerSegment flyPassengerSegment = flyPassengerSegments.get(i - 1);
                    if (flyPassengerSegment.getStatus().equals(SegmentStatus.RR.toString()) && flyPassengerSegment.getTicketStatus().equals(TicketStatus.OPEN_FOR_USE.toString())) {
                        FlyTicket flyTicket = flyTicketMapper.selectByPrimaryKey(flyPassengerSegment.getTicketId());
                        FlyPnr flyPnr = flyPnrMapper.selectByPrimaryKey(passenge.getPnrId());
                        try {
                            if (flyTicket == null)
                                throw new Exception("flyTicket null");
                            if (flyPnr == null)
                                throw new Exception("flyPnr null");
                            RefundParam refundParam = new RefundParam();
                            refundParam.setTicketNo(flyTicket.getIssCode() + "-" + flyTicket.getTicketNo());
                            refundParam.setSegId(i);
                            refundParam.setAmount(flyPassengerSegment.getNetFare().doubleValue());
                            refundParam.setCurrency(flyPassengerSegment.getCurrency());
                            String result = refundTicketCommand.trfd(refundParam);
                            if (!result.equals("OK"))
                                throw new Exception("Ticket Refund no OK");
                            flyPassengerSegment.setTicketStatus(TicketStatus.REFUNDED.toString());
                            flyPassengerSegment.setStatus(SegmentStatus.XX.toString());
                            flyPassengerSegmentMapper.updateByPrimaryKeySelective(flyPassengerSegment);
                            if (pnrCommand.pnrExist(flyPnr.getPnrNo()))
                                pnrCommand.cancelPnr(flyPnr.getPnrNo());
                            if (i == flyPassengerSegments.size()) {
                                RefundFormParam refundFormParam = new RefundFormParam();
                                refundFormParam.setAirlineCode(flyTicket.getIssCode());
                                refundFormParam.setTicketNo(flyTicket.getTicketNo());
                                refundFormParam.setPassName(formatName(passenge.getMingE(), passenge.getXingE()));
                                refundFormParam.setCurrency(order.getCurrency());
                                double grossRefund = flyPassengerSegment.getNetFare().doubleValue();
                                refundFormParam.setGrossRefund(grossRefund);
                                if (i == 1) {
                                    refundFormParam.setCouponNo("1000");
                                } else {
                                    refundFormParam.setCouponNo("1200");
                                }
                                double netRefund = (double) Math.round((grossRefund * refundPrice / orderPrice) * 100) / 100;
                                if (j != passengeVos.size()) {
                                    refundFormParam.setNetRefund(netRefund);
                                    refundFormParam.setDeduction(grossRefund - netRefund);
                                    rest = rest - netRefund;
                                } else {
                                    refundFormParam.setNetRefund(rest);
                                    refundFormParam.setDeduction(grossRefund - rest);
                                }
                                String s = refundTicketCommand.refundForm(refundFormParam);
                                System.out.println("退票单：" + s);
                            }
                        } catch (Exception e) {
                            System.out.println("退票异常 orderId:" + order.getOrderId());
                            log.error(e.getMessage(), e);
                            return JsonData.fail("Ticket Refund Failed orderId:" + order.getOrderId());
                        }
                    } else {
                        return JsonData.fail("Order not Issued orderId:" + order.getOrderId());
                    }
                }
            }
            String callBackResultStr = "";
            double amountDou = flyRefundReversal.getAmount() * 100;
            int amountInt = (new Double(amountDou)).intValue();
            String amount = String.valueOf(amountInt);
            try {
                callBackResultStr = HttpsUtils_p12.reversal(order.getFirstTransId(), amount);
            } catch (Exception e) {
                return JsonData.fail("Order Refund Failed orderId:" + order.getOrderId());
            }
            callBackResultStr = callBackResultStr.replaceAll("(\r\n|\r|\n|\n\r)", "<br>");
            if (callBackResultStr == null || callBackResultStr == "")
                return JsonData.fail("Order Refund Failed orderId:" + order.getOrderId());
            Map<String, String> callBackMap = new HashMap<String, String>();
            String[] data1 = callBackResultStr.split("<br>");
            if (data1 != null && data1.length > 0) {
                for (String s : data1) {
                    String[] data2 = s.split(":");
                    if (data2 != null && data2.length > 0)
                        callBackMap.put(data2[0].trim(), data2[1].trim());
                }
            }
            String result = callBackMap.get("RESULT"), result_code = callBackMap.get("RESULT_CODE"), refund_trans_id = callBackMap.get("REFUND_TRANS_ID");
            flyRefundReversal.setRefundStatus(result);
            flyRefundReversal.setRefundTransId(refund_trans_id);
            flyRefundReversal.setResult(callBackResultStr);
            flyRefundReversal.setRefoundTime(new Date());
            flyRefundReversalMapper.updateByPrimaryKeySelective(flyRefundReversal);
            if (callBackResultStr.toUpperCase().indexOf("ERROR") > -1 || org.apache.commons.lang3.StringUtils.isBlank(result) || !result.equals("OK"))
                return JsonData.fail("Order Refund Failed orderId:" + order.getOrderId());
            refundMail(orderNo, order.getContactEmail());
            order.setOrderStatus(OrderStatus.RF.toString());
            flyOrderMapper.updateByPrimaryKeySelective(order);
            integralService.refundIntegral(String.valueOf(order.getId()));
            return JsonData.success(null, "Order Refund Success!");
        } else {
            return JsonData.fail("Order Status Failed orderId:" + order.getOrderId());
        }
    }

    //退款
    public JsonData amountRefund(String orderNo) {
        FlyOrder order = flyOrderMapper.selectByPrimaryKey(Long.valueOf(orderNo));
        if (order != null && order.getOrderStatus().equalsIgnoreCase(OrderStatus.RD.toString())) {
            FlyRefundReversal flyRefundReversal = flyRefundReversalMapper.getByOrderId(Long.valueOf(orderNo));
            String callBackResultStr = "";
            double amountDou = flyRefundReversal.getAmount() * 100;
            int amountInt = (new Double(amountDou)).intValue();
            String amount = String.valueOf(amountInt);
            try {
                callBackResultStr = HttpsUtils_p12.reversal(order.getFirstTransId(), amount);
            } catch (Exception e) {
                return JsonData.fail("Order Refund Failed orderId:" + order.getOrderId());
            }
            callBackResultStr = callBackResultStr.replaceAll("(\r\n|\r|\n|\n\r)", "<br>");
            if (callBackResultStr == null || callBackResultStr == "")
                return JsonData.fail("Order Refund Failed orderId:" + order.getOrderId());
            Map<String, String> callBackMap = new HashMap<String, String>();
            String[] data1 = callBackResultStr.split("<br>");
            if (data1 != null && data1.length > 0) {
                for (String s : data1) {
                    String[] data2 = s.split(":");
                    if (data2 != null && data2.length > 0)
                        callBackMap.put(data2[0].trim(), data2[1].trim());
                }
            }
            String result = callBackMap.get("RESULT"), result_code = callBackMap.get("RESULT_CODE"), refund_trans_id = callBackMap.get("REFUND_TRANS_ID");
            flyRefundReversal.setRefundStatus(result);
            flyRefundReversal.setRefundTransId(refund_trans_id);
            flyRefundReversal.setResult(callBackResultStr);
            flyRefundReversal.setRefoundTime(new Date());
            flyRefundReversalMapper.updateByPrimaryKeySelective(flyRefundReversal);
            if (callBackResultStr.toUpperCase().indexOf("ERROR") > -1 || org.apache.commons.lang3.StringUtils.isBlank(result) || !result.equals("OK"))
                return JsonData.fail("Order Refund Failed orderId:" + order.getOrderId());
            refundMail(orderNo, order.getContactEmail());
            order.setOrderStatus(OrderStatus.RF.toString());
            flyOrderMapper.updateByPrimaryKeySelective(order);
            integralService.refundIntegral(String.valueOf(order.getId()));
            return JsonData.success(null, "Order Refund Success!");
        } else {
            return JsonData.fail("Order Status Failed orderId:" + order.getOrderId());
        }
    }

    //验证票号状态OPEN FOR USE true/false
    public boolean refundValid(String id) {
        FlyOrder order = flyOrderMapper.selectByPrimaryKey(Long.valueOf(id));
        List<FlyPassenge> passenges = flyPassengeMapper.getFlyPassengeByOrderId(id);
        try {
            for (FlyPassenge passenge : passenges) {
                List<FlyPassengerSegment> flyPassengerSegments = flyPassengerSegmentMapper.selectByOrderIdAndPassengerId(order.getId(), passenge.getId());
                FlyTicket flyTicket = flyTicketMapper.selectByPrimaryKey(flyPassengerSegments.get(0).getTicketId());
                boolean b = refundTicketCommand.ticketIsUse(flyTicket.getIssCode() + "-" + flyTicket.getTicketNo());
                if (!b) return false;
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            e.printStackTrace();
            return false;
        }
        return true;
    }

    //取消退款申请
    @Override
    public void refundClose(String id) {
        FlyOrder order = flyOrderMapper.selectByPrimaryKey(Long.valueOf(id));
        FlyRefundReversal flyRefundReversal = flyRefundReversalMapper.getByOrderId(Long.valueOf(id));
        refundCloseMail(order.getOrderId(), order.getContactEmail(), flyRefundReversal.getProcessedResult());
    }

    @Override
    public JsonData reIssue(String orderId) {
        if (StringUtils.isEmpty(orderId)) {
            return JsonData.fail("订单id是一个null值");
        }
        try {
            FlyOrder flyOrder = selectOrderDetailByOrderNo(orderId);
            if (!flyOrder.getOrderStatus().equalsIgnoreCase(OrderStatus.PF.getAlias())) {
                return JsonData.fail("此订单状态不是已出票 不能重新出票");
            }
            List<FlyPnrVo> pnrlist = flyPnrMapper.findAllPnrByOrderID(flyOrder.getId());
            Boolean isIssueFlag = false;
            for (FlyPnrVo pnr : pnrlist) {
                if (pnrCommand.pnrExist(pnr.getPnrNo()) && pnrCommand.isTicket(pnr.getPnrNo())) {
                    isIssueFlag = true;
                    break;
                }
            }
            if (isIssueFlag) {
                return ticketSuccess(orderId);
            }
            return JsonData.fail("该pnr已经出票");
        } catch (Exception e) {
            e.printStackTrace();
            return JsonData.fail("重新出票出现异常");
        }
    }

    //退款邮件
    private void refundMail(String orderNo, String address) {
        String segmentInfo = "";
        List<FlySegment> flySegments = flySegmentMapper.getFlySegmentListByOrderId(Long.valueOf(orderNo));
        for (FlySegment segment : flySegments) {
            segmentInfo = segmentInfo + (segment.getDepCode() + "-" + segment.getArrCode() + "/" + segment.getFlightNo() + "&nbsp;&nbsp;");
        }
        String context = "Dear&nbsp;customer,&nbsp;<br/><br/>We&nbsp;regret&nbsp;to&nbsp;inform&nbsp;you&nbsp;that&nbsp;your&nbsp;Myway&nbsp;Airlines&nbsp;flight&nbsp;&nbsp;" + segmentInfo + "&nbsp;was&nbsp;cancelled.&nbsp;<br/><br/>" +
                "Myway&nbsp;Airlines&nbsp;shall&nbsp;reimburse&nbsp;the&nbsp;full&nbsp;amount&nbsp;which&nbsp;you&nbsp;had&nbsp;paid&nbsp;for&nbsp;your&nbsp;ticket.&nbsp;The&nbsp;money&nbsp;will&nbsp;be&nbsp;transfered&nbsp;to&nbsp;your&nbsp;credit&nbsp;card&nbsp;account&nbsp;during&nbsp;3&nbsp;business&nbsp;days.&nbsp;<br/><br/>" +
                "We&nbsp;apologize&nbsp;for&nbsp;any&nbsp;inconvenience&nbsp;you&nbsp;had&nbsp;to&nbsp;face&nbsp;due&nbsp;to&nbsp;this&nbsp;flight&nbsp;cancellation&nbsp;and&nbsp;hope&nbsp;to&nbsp;see&nbsp;you&nbsp;on&nbsp;one&nbsp;of&nbsp;our&nbsp;flights&nbsp;in&nbsp;the&nbsp;future.&nbsp;<br/><br/>Sincerely&nbsp;Yours,";
        EmailUtils.sendHtmlEmail(address, "Myway Refund Information", context, null);
    }

    //取消退款申请
    private void refundCloseMail(String orderNo, String address, String reason) {
        String segmentInfo = "";
        List<FlySegment> flySegments = flySegmentMapper.getFlySegmentListByOrderId(Long.valueOf(orderNo));
        for (FlySegment segment : flySegments) {
            segmentInfo = segmentInfo + (segment.getDepCode() + "-" + segment.getArrCode() + "/" + segment.getFlightNo() + "&nbsp;&nbsp;");
        }
        String context = "Dear&nbsp;customer,&nbsp;<br/><br/>We&nbsp;regret&nbsp;to&nbsp;inform&nbsp;you&nbsp;that&nbsp;your&nbsp;Myway&nbsp;Airlines&nbsp;flight&nbsp;&nbsp;" + segmentInfo + "&nbsp;refund&nbsp;request&nbsp;rejected.&nbsp;<br/><br/>" +
                "Specific&nbsp;reasons:" + reason + "<br/><br/>Sincerely&nbsp;Yours,";
        EmailUtils.sendHtmlEmail(address, "Myway Refund Rejected Information", context, null);
    }


}
